/*
* clapack.cpp
* 
* Copyright (c) 2003-2004, .NET Analytics Project. All rights reserved.
*/

extern "C" {
	#include <vecLib/vecLib.h>
}

#include <algorithm>
using namespace std;

extern "C" {
	inline char getTchar(const CBLAS_TRANSPOSE trans){
		char cTrans;
		switch( trans ){
			case  CblasNoTrans : cTrans = 'N';
				break;
			case  CblasTrans : cTrans = 'T';
				break;
			case  CblasConjTrans : cTrans = 'C';
				break;
		}
		return cTrans;
	}
	
	inline char getSchar(const CBLAS_SIDE side){
		char cSide;
		switch( side ){
			case  CblasLeft : cSide= 'L';
				break;
			case  CblasRight : cSide = 'R';
				break;
		}
		return cSide;
	}

    inline char getUchar(const CBLAS_UPLO uplo){
        char cUplo;
        switch( uplo ){
            case CblasLower : cUplo = 'L';
                break;
            case CblasUpper : cUplo = 'U';
                break;
        }
        return cUplo;
    }


	__CLPK_integer dna_lapack_sormbr( __CLPK_integer block_size, char vect, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, float* a, __CLPK_integer lda, float* tau, float* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		float* work = new float[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		sormbr_(&vect, &sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_dormbr( __CLPK_integer block_size, char vect, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, double* a, __CLPK_integer lda, double* tau, double* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		double* work = new double[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		dormbr_(&vect, &sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_cunmbr( __CLPK_integer block_size, char vect, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_complex* a, __CLPK_integer lda, __CLPK_complex* tau, __CLPK_complex* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		__CLPK_complex* work = new __CLPK_complex[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		cunmbr_(&vect, &sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_zunmbr( __CLPK_integer block_size,  char vect, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_doublecomplex* a, __CLPK_integer lda, __CLPK_doublecomplex* tau, __CLPK_doublecomplex* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		zunmbr_(&vect, &sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_cungbr(__CLPK_integer block_size, char vect, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_complex* a, __CLPK_integer lda, __CLPK_complex* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = min(m,n)*block_size;
		__CLPK_complex* work = new __CLPK_complex[lwork];
		cungbr_(&vect, &m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_zungbr(__CLPK_integer block_size, char vect, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_doublecomplex* a, __CLPK_integer lda, __CLPK_doublecomplex* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = min(m,n)*block_size;
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		zungbr_(&vect, &m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_sorgbr(__CLPK_integer block_size, char vect, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, float* a, __CLPK_integer lda, float* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = min(m,n)*block_size;
		float* work = new float[lwork];
		sorgbr_(&vect, &m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_dorgbr(__CLPK_integer block_size, char vect, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, double* a, __CLPK_integer lda, double* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = min(m,n)*block_size;
		double* work = new double[lwork];
		dorgbr_(&vect, &m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_sgebrd(__CLPK_integer block_size,__CLPK_integer m, __CLPK_integer n, float* a, __CLPK_integer lda, float* d, float* e, float* tauq, float* taup ){
		__CLPK_integer info;
		__CLPK_integer lwork = (m + n)*block_size;
		float* work = new float[lwork];
		sgebrd_(&m, &n, a, &lda, d, e, tauq, taup, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_dgebrd(__CLPK_integer block_size,__CLPK_integer m, __CLPK_integer n, double* a, __CLPK_integer lda, double* d, double* e, double* tauq, double* taup ){
		__CLPK_integer info;
		__CLPK_integer lwork = (m + n)*block_size;
		double* work = new double[lwork];
		dgebrd_(&m, &n, a, &lda, d, e, tauq, taup, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_cgebrd(__CLPK_integer block_size,__CLPK_integer m, __CLPK_integer n, __CLPK_complex* a, __CLPK_integer lda, float* d, float* e, __CLPK_complex* tauq, __CLPK_complex* taup ){
		__CLPK_integer info;
		__CLPK_integer lwork = (m + n)*block_size;
		__CLPK_complex* work = new __CLPK_complex[lwork];
		cgebrd_(&m, &n, a, &lda, d, e, tauq, taup, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_zgebrd(__CLPK_integer block_size,__CLPK_integer m, __CLPK_integer n, __CLPK_doublecomplex* a, __CLPK_integer lda, double* d, double* e, __CLPK_doublecomplex* tauq, __CLPK_doublecomplex* taup ){
		__CLPK_integer info;
		__CLPK_integer lwork = (m + n)*block_size;
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		zgebrd_(&m, &n, a, &lda, d, e, tauq, taup, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_sgeqp3(__CLPK_integer m, __CLPK_integer n, float* a, __CLPK_integer lda, __CLPK_integer* jpvt, float* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = 3*n+1;
		float* work = new float[lwork];
		sgeqp3_(&m, &n, a, &lda, jpvt, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_dgeqp3(__CLPK_integer m, __CLPK_integer n, double* a, __CLPK_integer lda, __CLPK_integer* jpvt, double* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = 3*n+1;
		double* work = new double[lwork];
		dgeqp3_(&m, &n, a, &lda, jpvt, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_cgeqp3(__CLPK_integer m, __CLPK_integer n, __CLPK_complex* a, __CLPK_integer lda, __CLPK_integer* jpvt, __CLPK_complex* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = n+1;
		__CLPK_complex* work = new __CLPK_complex[lwork];
		float* rwork = new float[2*n];
		cgeqp3_(&m, &n, a, &lda, jpvt, tau, work, &lwork, rwork, &info);
		delete[] work;
		delete[] rwork;
		return info;
	}

	__CLPK_integer dna_lapack_zgeqp3(__CLPK_integer m, __CLPK_integer n, __CLPK_doublecomplex* a, __CLPK_integer lda, __CLPK_integer* jpvt, __CLPK_doublecomplex* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = n+1;
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		double* rwork = new double[2*n];
		zgeqp3_(&m, &n, a, &lda, jpvt, tau, work, &lwork, rwork, &info);
		delete[] work;
		delete[] rwork;
		return info;
	}
	
	__CLPK_integer dna_lapack_sormqr(__CLPK_integer block_size,CBLAS_SIDE side, CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, float* a, __CLPK_integer lda, float* tau, float* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		float* work = new float[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		sormqr_(&sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_dormqr(__CLPK_integer block_size,const CBLAS_SIDE side, const CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, double* a, __CLPK_integer lda, double* tau, double* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		double* work = new double[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		dormqr_(&sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_cunmqr(__CLPK_integer block_size,const CBLAS_SIDE side, const CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_complex* a, __CLPK_integer lda, __CLPK_complex* tau, __CLPK_complex* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		__CLPK_complex* work = new __CLPK_complex[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		cunmqr_(&sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_zunmqr(__CLPK_integer block_size,const CBLAS_SIDE side, const CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_doublecomplex* a, __CLPK_integer lda, __CLPK_doublecomplex* tau, __CLPK_doublecomplex* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		zunmqr_(&sChar, &tChar, &m, &n, &k, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}
	
	__CLPK_integer dna_lapack_sorgqr(__CLPK_integer block_size, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, float* a, __CLPK_integer lda, float* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		float* work = new float[lwork];
		sorgqr_(&m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_dorgqr( __CLPK_integer block_size, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, double* a, __CLPK_integer lda, double* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		double* work = new double[lwork];
		dorgqr_(&m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_cungqr( __CLPK_integer block_size, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_complex* a, __CLPK_integer lda, __CLPK_complex* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		__CLPK_complex* work = new __CLPK_complex[lwork];
		cungqr_(&m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_zungqr( __CLPK_integer block_size, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_doublecomplex* a, __CLPK_integer lda, __CLPK_doublecomplex* tau ){
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		zungqr_(&m, &n, &k, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

    __CLPK_integer dna_lapack_sgetrs(const CBLAS_TRANSPOSE trans, __CLPK_integer n, __CLPK_integer nrhs, float* a, __CLPK_integer lda, __CLPK_integer* ipiv, float* b,__CLPK_integer ldb ){
		__CLPK_integer info;
		char tChar = getTchar(trans);
		int size = max((long)1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		sgetrs_(&tChar, &n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	__CLPK_integer dna_lapack_dgetrs(const CBLAS_TRANSPOSE trans, __CLPK_integer n, __CLPK_integer nrhs, double* a, __CLPK_integer lda, __CLPK_integer* ipiv, double* b,__CLPK_integer ldb ){
		__CLPK_integer info;
		int size = max((long)1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		char tChar = getTchar(trans);
		dgetrs_(&tChar, &n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	__CLPK_integer dna_lapack_cgetrs(const CBLAS_TRANSPOSE trans, __CLPK_integer n, __CLPK_integer nrhs, __CLPK_complex* a, __CLPK_integer lda, __CLPK_integer* ipiv, __CLPK_complex* b,__CLPK_integer ldb ){
		__CLPK_integer info;
		int size = max((long)1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		char tChar = getTchar(trans);
		cgetrs_(&tChar, &n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	__CLPK_integer  dna_lapack_zgetrs(const CBLAS_TRANSPOSE trans, __CLPK_integer n, __CLPK_integer nrhs, __CLPK_doublecomplex* a, __CLPK_integer lda, __CLPK_integer* ipiv, __CLPK_doublecomplex* b,__CLPK_integer ldb ){
		__CLPK_integer info;
		int size = max((long)1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		char tChar = getTchar(trans);
		zgetrs_(&tChar, &n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	__CLPK_integer  dna_lapack_sgesv(__CLPK_integer n, __CLPK_integer nrhs, float* a, __CLPK_integer lda, __CLPK_integer* ipiv, float* b, __CLPK_integer ldb ){
		__CLPK_integer info;
		sgesv_(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		return info;
	}

	__CLPK_integer  dna_lapack_dgesv(__CLPK_integer n, __CLPK_integer nrhs, double* a, __CLPK_integer lda, __CLPK_integer* ipiv, double* b, __CLPK_integer ldb ){
		__CLPK_integer info;
		dgesv_(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		return info;
	}

	__CLPK_integer  dna_lapack_cgesv(__CLPK_integer n, __CLPK_integer nrhs, __CLPK_complex* a, __CLPK_integer lda, __CLPK_integer* ipiv, __CLPK_complex* b, __CLPK_integer ldb ){
		__CLPK_integer info;
		cgesv_(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		return info;
	}

	__CLPK_integer  dna_lapack_zgesv(__CLPK_integer n, __CLPK_integer nrhs, __CLPK_doublecomplex* a, __CLPK_integer lda, __CLPK_integer* ipiv, __CLPK_doublecomplex* b, __CLPK_integer ldb ){
		__CLPK_integer info;
		zgesv_(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info);
		return info;
	}

	__CLPK_integer  dna_lapack_sgetri(__CLPK_integer block_size, __CLPK_integer n, float* a, __CLPK_integer lda, __CLPK_integer* ipiv ){
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		int size = max((long)1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		float* work = new float[lwork];
		sgetri_(&n,a,&lda,ipiv,work,&lwork,&info);
		delete[] work;
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	__CLPK_integer  dna_lapack_dgetri(__CLPK_integer block_size, __CLPK_integer n, double* a, __CLPK_integer lda, __CLPK_integer* ipiv ){
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		int size = max((long)1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		double* work = new double[lwork];
		dgetri_(&n,a,&lda,ipiv,work,&lwork,&info);
		delete[] work;
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}
	
	__CLPK_integer  dna_lapack_cgetri(__CLPK_integer block_size, __CLPK_integer n, __CLPK_complex* a, __CLPK_integer lda, __CLPK_integer* ipiv ){
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		int size = max((long)1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		__CLPK_complex* work = new __CLPK_complex[lwork];
		cgetri_(&n,a,&lda,ipiv,work,&lwork,&info);
		delete[] work;
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	__CLPK_integer  dna_lapack_zgetri(__CLPK_integer block_size, __CLPK_integer n, __CLPK_doublecomplex* a, __CLPK_integer lda, __CLPK_integer* ipiv ){
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		int size = max((long)1,n);
		for(int i = 0; i < size; ++i ){
			ipiv[i] += 1;
		}
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		zgetri_(&n,a,&lda,ipiv,work,&lwork,&info);
		delete[] work;
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	__CLPK_integer  dna_lapack_sgetrf(__CLPK_integer m, __CLPK_integer n, float* a, __CLPK_integer lda, __CLPK_integer *ipiv){
		__CLPK_integer info;
		sgetrf_(&m,&n,a,&lda,ipiv,&info);
		int size = max((long)1,min(m,n));
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	__CLPK_integer  dna_lapack_dgetrf(__CLPK_integer m, __CLPK_integer n, double *a, __CLPK_integer lda, __CLPK_integer *ipiv){
		__CLPK_integer info;
		dgetrf_(&m,&n,a,&lda,ipiv,&info);
		int size = max((long)1,min(m,n));
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}
	
	__CLPK_integer  dna_lapack_cgetrf(__CLPK_integer m, __CLPK_integer n, __CLPK_complex *a, __CLPK_integer lda, __CLPK_integer *ipiv){
		__CLPK_integer info;
		cgetrf_(&m,&n,a,&lda,ipiv,&info);
		int size = max((long)1,min(m,n));
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}
	
	__CLPK_integer  dna_lapack_zgetrf(__CLPK_integer m, __CLPK_integer n, __CLPK_doublecomplex *a, __CLPK_integer lda, __CLPK_integer *ipiv){
		__CLPK_integer info;
		zgetrf_(&m,&n,a,&lda,ipiv,&info);
		int size = max((long)1,min(m,n));
		for(int i = 0; i < size; ++i ){
			ipiv[i] -= 1;
		}
		return info;
	}

	__CLPK_integer  dna_lapack_spotrf(const CBLAS_UPLO uplo, __CLPK_integer n, float *a, __CLPK_integer lda){
        __CLPK_integer info;
        char uChar = getUchar(uplo);
        spotrf_(&uChar, &n, a, &lda, &info);
        return info;
    }

	__CLPK_integer  dna_lapack_dpotrf(const CBLAS_UPLO uplo, __CLPK_integer n, double *a, __CLPK_integer lda) {
        __CLPK_integer info;
        char uChar = getUchar(uplo);
        dpotrf_(&uChar, &n, a, &lda, &info);
        return info;
	}

	__CLPK_integer  dna_lapack_cpotrf(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_complex *a, __CLPK_integer lda) {
        __CLPK_integer info;
        char uChar = getUchar(uplo);
        cpotrf_(&uChar, &n, a, &lda, &info);
        return info;
	}

	__CLPK_integer  dna_lapack_zpotrf(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_doublecomplex *a, __CLPK_integer lda) {
        __CLPK_integer info;
        char uChar = getUchar(uplo);
        zpotrf_(&uChar, &n, a, &lda, &info);
        return info;
	}

	__CLPK_integer  dna_lapack_spotrs(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_integer nrhs, float *a, __CLPK_integer lda, float *b, __CLPK_integer ldb) {
        __CLPK_integer info;
        char uChar = getUchar(uplo);
        spotrs_(&uChar, &n, &nrhs, a, &lda, b, &ldb, &info);
        return info;
	}

	__CLPK_integer  dna_lapack_dpotrs(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_integer nrhs, double *a, __CLPK_integer lda, double *b, __CLPK_integer ldb) {
        __CLPK_integer info;
        char uChar = getUchar(uplo);
        dpotrs_(&uChar, &n, &nrhs, a, &lda, b, &ldb, &info);
        return info;
	}

	__CLPK_integer  dna_lapack_cpotrs(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_integer nrhs, __CLPK_complex *a, __CLPK_integer lda, __CLPK_complex *b, __CLPK_integer ldb) {
        __CLPK_integer info;
        char uChar = getUchar(uplo);
        cpotrs_(&uChar, &n, &nrhs, a, &lda, b, &ldb, &info);
        return info;
	}

	__CLPK_integer  dna_lapack_zpotrs(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_integer nrhs, __CLPK_doublecomplex *a, __CLPK_integer lda, __CLPK_doublecomplex *b, __CLPK_integer ldb) {
        __CLPK_integer info;
        char uChar = getUchar(uplo);
        zpotrs_(&uChar, &n, &nrhs, a, &lda, b, &ldb, &info);
        return info;
	}

	__CLPK_integer  dna_lapack_spocon(const CBLAS_UPLO uplo, __CLPK_integer n, float *a, __CLPK_integer lda, float anorm, float *rcond) {
		__CLPK_integer info;
		float* work = new float[3*n];
		__CLPK_integer* iwork = new __CLPK_integer[n];
		char uChar = getUchar(uplo);
		spocon_(&uChar, &n, a, &lda, &anorm, rcond, work, iwork, &info);
		delete[] work;
		delete[] iwork;
		return info;
	}

	__CLPK_integer  dna_lapack_dpocon(const CBLAS_UPLO uplo, __CLPK_integer n, double *a, __CLPK_integer lda, double anorm, double *rcond) {
		__CLPK_integer info;
		double* work = new double[3*n];
		__CLPK_integer* iwork = new __CLPK_integer[n];
		char uChar = getUchar(uplo);
		dpocon_(&uChar, &n, a, &lda, &anorm, rcond, work, iwork, &info);
		delete[] work;
		delete[] iwork;
		return info;
	}

	__CLPK_integer  dna_lapack_cpocon(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_complex *a, __CLPK_integer lda, float anorm, float *rcond) {
		__CLPK_integer info;
		__CLPK_complex* work = new __CLPK_complex[2*n];
		float* rwork = new float[n];
		char uChar = getUchar(uplo);
		cpocon_(&uChar, &n, a, &lda, &anorm, rcond, work, rwork, &info);
		delete[] work;
		delete[] rwork;
		return info;
	}

	__CLPK_integer  dna_lapack_zpocon(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_doublecomplex *a, __CLPK_integer lda, double anorm, double *rcond) {
		__CLPK_integer info;
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[2*n];
		double* rwork = new double[n];
		char uChar = getUchar(uplo);
		zpocon_(&uChar, &n, a, &lda, &anorm, rcond, work, rwork, &info);
		delete[] work;
		delete[] rwork;
		return info;
	}

	__CLPK_integer  dna_lapack_spotri(const CBLAS_UPLO uplo, __CLPK_integer n, float *a, __CLPK_integer lda) {
		__CLPK_integer info;
		char uChar = getUchar(uplo);
		spotri_(&uChar, &n, a, &lda, &info);
		return info;
	}

	__CLPK_integer  dna_lapack_dpotri(const CBLAS_UPLO uplo, __CLPK_integer n, double *a, __CLPK_integer lda) {
		__CLPK_integer info;
		char uChar = getUchar(uplo);
		dpotri_(&uChar, &n, a, &lda, &info);
		return info;
	}

	__CLPK_integer  dna_lapack_cpotri(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_complex *a, __CLPK_integer lda) {
		__CLPK_integer info;
		char uChar = getUchar(uplo);
		cpotri_(&uChar, &n, a, &lda, &info);
		return info;
	}

	__CLPK_integer  dna_lapack_zpotri(const CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_doublecomplex *a, __CLPK_integer lda) {
		__CLPK_integer info;
		char uChar = getUchar(uplo);
		zpotri_(&uChar, &n, a, &lda, &info);
		return info;
	}

	__CLPK_integer  dna_lapack_sgehrd(__CLPK_integer block_size, __CLPK_integer n, __CLPK_integer ilo, __CLPK_integer ihi, float *a, __CLPK_integer lda, float *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		float* work = new float[lwork];
		sgehrd_(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_dgehrd(__CLPK_integer block_size, __CLPK_integer n, __CLPK_integer ilo, __CLPK_integer ihi, double *a, __CLPK_integer lda, double *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		double* work = new double[lwork];
		dgehrd_(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_cgehrd(__CLPK_integer block_size, __CLPK_integer n, __CLPK_integer ilo, __CLPK_integer ihi, __CLPK_complex *a, __CLPK_integer lda, __CLPK_complex *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		__CLPK_complex* work = new __CLPK_complex[lwork];
		cgehrd_(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_zgehrd(__CLPK_integer block_size, __CLPK_integer n, __CLPK_integer ilo, __CLPK_integer ihi, __CLPK_doublecomplex *a, __CLPK_integer lda, __CLPK_doublecomplex *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = block_size*n;
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		zgehrd_(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_sorghr(__CLPK_integer block_size, __CLPK_integer n, __CLPK_integer ilo, __CLPK_integer ihi, float *a, __CLPK_integer lda, float *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = max(ihi-ilo,(__CLPK_integer)1)*block_size;
		float* work = new float[lwork];
		sorghr_(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_dorghr(__CLPK_integer block_size, __CLPK_integer n, __CLPK_integer ilo, __CLPK_integer ihi, double *a, __CLPK_integer lda, double *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = max(ihi-ilo,(__CLPK_integer)1)*block_size;
		double* work = new double[lwork];
		dorghr_(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_cunghr(__CLPK_integer block_size, __CLPK_integer n, __CLPK_integer ilo, __CLPK_integer ihi, __CLPK_complex *a, __CLPK_integer lda, __CLPK_complex *tau){
		__CLPK_integer info;
		__CLPK_integer lwork = max(ihi-ilo,(__CLPK_integer)1)*block_size;
		__CLPK_complex* work = new __CLPK_complex[lwork];
		cunghr_(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_zunghr(__CLPK_integer block_size, __CLPK_integer n, __CLPK_integer ilo, __CLPK_integer ihi, __CLPK_doublecomplex *a, __CLPK_integer lda, __CLPK_doublecomplex *tau){
		__CLPK_integer info;
		__CLPK_integer lwork = max(ihi-ilo,(__CLPK_integer)1)*block_size;
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		zunghr_(&n, &ilo, &ihi, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_sormhr(__CLPK_integer block_size, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_integer ilo, __CLPK_integer ihi, float* a, __CLPK_integer lda, float* tau, float* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		float* work = new float[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		sormhr_(&sChar, &tChar, &m, &n, &ilo, &ihi, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_dormhr(__CLPK_integer block_size, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_integer ilo, __CLPK_integer ihi, double* a, __CLPK_integer lda, double* tau, double* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		double* work = new double[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		dormhr_(&sChar, &tChar, &m, &n, &ilo, &ihi, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_cunmhr(__CLPK_integer block_size, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_integer ilo, __CLPK_integer ihi, __CLPK_complex* a, __CLPK_integer lda, __CLPK_complex* tau, __CLPK_complex* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		__CLPK_complex* work = new __CLPK_complex[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		cunmhr_(&sChar, &tChar, &m, &n, &ilo, &ihi, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer  dna_lapack_zunmhr(__CLPK_integer block_size, CBLAS_SIDE side, CBLAS_TRANSPOSE trans, __CLPK_integer m, __CLPK_integer n, __CLPK_integer k, __CLPK_integer ilo, __CLPK_integer ihi, __CLPK_doublecomplex* a, __CLPK_integer lda, __CLPK_doublecomplex* tau, __CLPK_doublecomplex* c, __CLPK_integer ldc ){
		__CLPK_integer info;
		__CLPK_integer lwork;
		if( side == CblasLeft ){
			lwork = block_size*n;
		}else{
			lwork = block_size*m;
		}
		__CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
		char tChar = getTchar(trans);
		char sChar = getSchar(side);
		zunmhr_(&sChar, &tChar, &m, &n, &ilo, &ihi, a, &lda, tau, c, &ldc, work, &lwork, &info);
		delete[] work;
		return info;
	}

    __CLPK_integer dna_lapack_sbdsqr(CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_integer ncvt, __CLPK_integer nru, __CLPK_integer ncc, float* d, float* e, float* vt, __CLPK_integer ldvt, float* u, __CLPK_integer ldu, float* c, __CLPK_integer ldc ){
        __CLPK_integer info;
        __CLPK_integer lwork;
        if( ncvt == nru == ncc == 0 ){
            lwork = max((__CLPK_integer)1,2*n);
        }else{
            lwork = max((__CLPK_integer)1,4*(n-1));
        }

        float* work = new float[lwork];
        char uChar = getUchar(uplo);
        sbdsqr_(&uChar, &n, &ncvt, &nru, &ncc, d, e, vt, &ldvt, u, &ldu, c, &ldc, work, &info);
        delete[] work;
        return info;
    }

    __CLPK_integer dna_lapack_dbdsqr(CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_integer ncvt, __CLPK_integer nru, __CLPK_integer ncc, double* d, double* e, double* vt, __CLPK_integer ldvt, double* u, __CLPK_integer ldu, double* c, __CLPK_integer ldc ){
        __CLPK_integer info;
        __CLPK_integer lwork;
        if( ncvt == nru == ncc == 0 ){
            lwork = max((__CLPK_integer)1,2*n);
        }else{
            lwork = max((__CLPK_integer)1,4*(n-1));
        }

        double* work = new double[lwork];
        char uChar = getUchar(uplo);
        dbdsqr_(&uChar, &n, &ncvt, &nru, &ncc, d, e, vt, &ldvt, u, &ldu, c, &ldc, work, &info);
        delete[] work;
        return info;
    }

    __CLPK_integer  dna_lapack_cbdsqr(CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_integer ncvt, __CLPK_integer nru, __CLPK_integer ncc, float* d, float* e, __CLPK_complex* vt, __CLPK_integer ldvt, __CLPK_complex* u, __CLPK_integer ldu, __CLPK_complex* c, __CLPK_integer ldc ){
        __CLPK_integer info;
        __CLPK_integer lwork;
        if( ncvt == nru == ncc == 0 ){
            lwork = max((__CLPK_integer)1,2*n);
        }else{
            lwork = max((__CLPK_integer)1,4*(n-1));
        }

        float* work = new float[lwork];
        char uChar = getUchar(uplo);
        cbdsqr_(&uChar, &n, &ncvt, &nru, &ncc, d, e, vt, &ldvt, u, &ldu, c, &ldc, work, &info);
        delete[] work;
        return info;
    }

    __CLPK_integer  dna_lapack_zbdsqr(CBLAS_UPLO uplo, __CLPK_integer n, __CLPK_integer ncvt, __CLPK_integer nru, __CLPK_integer ncc, double* d, double* e, __CLPK_doublecomplex* vt, __CLPK_integer ldvt, __CLPK_doublecomplex* u, __CLPK_integer ldu, __CLPK_doublecomplex* c, __CLPK_integer ldc ){
        __CLPK_integer info;
        __CLPK_integer lwork;
        if( ncvt == nru == ncc == 0 ){
            lwork = max((__CLPK_integer)1,2*n);
        }else{
            lwork = max((__CLPK_integer)1,4*(n-1));
        }

        double* work = new double[lwork];
        char uChar = getUchar(uplo);
        zbdsqr_(&uChar, &n, &ncvt, &nru, &ncc, d, e, vt, &ldvt, u, &ldu, c, &ldc, work, &info);
        delete[] work;
        return info;
    }

    __CLPK_integer dna_lapack_sgesvd(__CLPK_integer m, __CLPK_integer n, float* a, __CLPK_integer lda, float* s, float* u, __CLPK_integer ldu, float* vt, __CLPK_integer ldvt ){
        __CLPK_integer info;
        __CLPK_integer lwork = max(3*min(m,n)+max(m,n), 5*min(m,n));
        float* work = new float[lwork];
        char S = 'S';
		char A = 'A';
        sgesvd_( &A, &A, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info );
        delete[] work;
        return info;
    }

    __CLPK_integer  dna_lapack_dgesvd(__CLPK_integer m, __CLPK_integer n, double* a, __CLPK_integer lda, double* s, double* u, __CLPK_integer ldu, double* vt, __CLPK_integer ldvt ){
        __CLPK_integer info;
        __CLPK_integer lwork = max(3*min(m,n)+max(m,n), 5*min(m,n));
        double* work = new double[lwork];
        char S = 'S';
		char A = 'A';
        dgesvd_( &A, &S, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info );
        delete[] work;
        return info;
    }
	
	//for some reason this isn't in clapack.h
    extern "C"{
        __CLPK_integer cgesvd_( char*, char*, __CLPK_integer*, __CLPK_integer*, __CLPK_complex*, __CLPK_integer*, float*, __CLPK_complex *, __CLPK_integer*, 
                 __CLPK_complex*, __CLPK_integer*, __CLPK_complex*, __CLPK_integer*, float*, __CLPK_integer*);
    }
    __CLPK_integer  dna_lapack_cgesvd(__CLPK_integer m, __CLPK_integer n, __CLPK_complex* a, __CLPK_integer lda, float* s, __CLPK_complex* u, __CLPK_integer ldu, __CLPK_complex* vt, __CLPK_integer ldvt ){
        __CLPK_integer info;
        __CLPK_integer lwork = 2*min(m,n)+max(m,n);
        float* rwork = new float[max((long)1, 5*min(m,n))];
        __CLPK_complex* work = new __CLPK_complex[lwork];
        char S = 'S';
		char A = 'A';
        cgesvd_( &A, &A, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, rwork, &info );
        delete[] work;
        return info;
    }

	//for some reason this isn't in clapack.h
    extern "C"{
        __CLPK_integer zgesvd_( char*, char*, __CLPK_integer*, __CLPK_integer*, __CLPK_doublecomplex*, __CLPK_integer*, double*, __CLPK_doublecomplex*, __CLPK_integer*, 
                 __CLPK_doublecomplex*, __CLPK_integer*, __CLPK_doublecomplex*, __CLPK_integer*, double*, __CLPK_integer*);
    }
    __CLPK_integer  dna_lapack_zgesvd(__CLPK_integer m, __CLPK_integer n, __CLPK_doublecomplex* a, __CLPK_integer lda, double* s, __CLPK_doublecomplex* u, __CLPK_integer ldu, __CLPK_doublecomplex* vt, __CLPK_integer ldvt ){
        __CLPK_integer info;
        __CLPK_integer lwork = 2*min(m,n)+max(m,n);
        double* rwork = new double[max((long)1, 5*min(m,n))];
        __CLPK_doublecomplex* work = new __CLPK_doublecomplex[lwork];
        char S = 'S';
		char A = 'A';
        zgesvd_( &A, &A, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, rwork, &info );
        delete[] work;
        return info;
    }
	
	
	__CLPK_integer dna_lapack_sgeqrf(__CLPK_integer block_size, __CLPK_integer m, __CLPK_integer n, float *a, __CLPK_integer lda, float *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = max((long)1,block_size*n);
		float *work = new float[lwork];
		sgeqrf_(&m, &n, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_dgeqrf(__CLPK_integer block_size, __CLPK_integer m, __CLPK_integer n, double *a, __CLPK_integer lda, double *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = max((long)1,block_size*n);
		double *work = new double[lwork];
		dgeqrf_(&m, &n, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_cgeqrf(__CLPK_integer block_size, __CLPK_integer m, __CLPK_integer n, __CLPK_complex *a, __CLPK_integer lda, __CLPK_complex *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = max((long)1,block_size*n);
		__CLPK_complex *work = new __CLPK_complex[lwork];
		cgeqrf_(&m, &n, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

	__CLPK_integer dna_lapack_zgeqrf(__CLPK_integer block_size, __CLPK_integer m, __CLPK_integer n, __CLPK_doublecomplex *a, __CLPK_integer lda, __CLPK_doublecomplex *tau) {
		__CLPK_integer info;
		__CLPK_integer lwork = max((long)1,block_size*n);
		__CLPK_doublecomplex *work = new __CLPK_doublecomplex[lwork];
		zgeqrf_(&m, &n, a, &lda, tau, work, &lwork, &info);
		delete[] work;
		return info;
	}

}

